using System;
using System.IO;
using System.Collections.Generic;
using needle.Services.astra.Collections;

namespace needle.Services.astra.Collections
{
	/// <summary>
	/// List of documents open/saved to files on OS file system.
	/// </summary>
	public abstract class FileDocuments : Documents
	{
		/// <summary>
		/// Gets absolute file path from <see cref="uri"/>.
		/// </summary>
		/// <param name="uri">Uri.</param>
		/// <returns><see cref="Uri.LocalPath"/>.</returns>
		public virtual string GetFilePath(Uri uri)
		{
			return uri.LocalPath;
		}

		/// <summary>
		/// See <see cref="Documents.Open(Uri, bool)"/>.
		/// Calls <see cref="Open(string, bool"/>.
		/// </summary>
		/// <param name="uri">Uri.</param>
		/// <param name="readOnly">Whether to use read only mode.</param>
		/// <returns>Document.</returns>
		protected override IDocument Open(Uri uri, bool readOnly)
		{
			return Open(GetFilePath(uri), readOnly);
		}
		/// <summary>
		/// See <see cref="Documents.Save(IDocument, Uri)"/>.
		/// Deletes file at <paramref name="uri"/> and calls <see cref="Save(IDocument, string)"/>.
		/// </summary>
		/// <param name="document">Document.</param>
		/// <param name="uri">Uri.</param>
		protected override void Save(IDocument document, Uri uri)
		{
			string filePath = GetFilePath(uri);
			File.Delete(filePath);
			Save(document, filePath);
		}
		/// <summary>
		/// Actually opens document.
		/// </summary>
		/// <param name="filePath">Document path.</param>
		/// <param name="readOnly">Whether to use read only mode.</param>
		/// <returns>Document.</returns>
		protected abstract IDocument Open(string filePath, bool readOnly);
		/// <summary>
		/// Actually saves document.
		/// </summary>
		/// <param name="document">Document.</param>
		/// <param name="filePath">Document path.</param>
		protected abstract void Save(IDocument document, string filePath);
		/// <summary>
		/// See <see cref="Documents.DoBackup"/>.
		/// Makes backup copy (<see cref="File.Copy"/> with replace true) of file at <paramref name="sourceUri"/> to <paramref name="targetUri"/>.
		/// Uris are translated with <see cref="GetFilePath"/>.
		/// </summary>
		/// <param name="sourceUri">Source uri.</param>
		/// <param name="targetUri">Target uri.</param>
		protected override void DoBackup(Uri sourceUri, Uri targetUri)
		{
			string sourcePath = GetFilePath(sourceUri);
			string targetPath = GetFilePath(targetUri);
			File.Copy(sourcePath, targetPath, true);
		}
		/// <summary>
		/// See <see cref="Documents.DoesExist(Uri)"/>.
		/// </summary>
		/// <param name="uri">Uri.</param>
		/// <returns><see cref="File.Exists"/> for <see cref="GetFilePath"/>.</returns>
		protected override bool DoesExist(Uri uri)
		{
			return File.Exists(GetFilePath(uri));
		}
		/// <summary>
		/// See <see cref="Documents.DoValidate(Uri)"/>.
		/// </summary>
		/// <param name="uri">Uri.</param>
		/// <exception cref="ArgumentException">
		/// <paramref name="uri"/> does not represent a file (<see cref="Uri.IsFile"/> is false).
		/// </exception>
		protected override void DoValidate(Uri uri)
		{
			if (!uri.IsFile)
				throw new ArgumentException("Uri does not represent a file.", "uri");
		}
	}
}
